package com.ben.utils.flow

import com.ben.utils.ext.*
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch

/**
 * Author: bin.yang
 * Maintainer: bin.yang
 * Date: 2021/10/11
 * Copyright: 2021 Inc. All rights reserved.
 * Desc:
 */
class FlowScope {

    var scope: CoroutineScope

    constructor(name: String) {
        scope = CoroutineScope(CoroutineName(name))
    }

    constructor(scope: CoroutineScope) {
        this.scope = scope
    }

    fun launchMain(delayTime: Long = 0L, func: suspend CoroutineScope.() -> Unit): Job {
        return scope.launchMain(delayTime) { func.invoke(this) }
    }

    fun launchIO(delayTime: Long = 0L, func: suspend CoroutineScope.() -> Unit): Job {
        return scope.launchIO(delayTime) { func.invoke(this) }
    }

    fun launch(func: suspend CoroutineScope.() -> Unit): Job {
        return scope.launch { func.invoke(this) }
    }

    fun <T> collect(flow: Flow<T>, func: suspend CoroutineScope.(T) -> Unit) =
        scope.collect(flow, func)

    fun <T> collect(flow: XSharedFlow<T>, func: suspend CoroutineScope.(T) -> Unit) =
        scope.collect(flow, func)

    fun <T> collectWithEnd(
        flow: Flow<T>,
        func: suspend CoroutineScope.(T) -> Unit,
        predicate: suspend (T) -> Boolean
    ) = scope.collectWithEnd(flow, func, predicate)

    fun <T> collectOnce(flow: Flow<T>, func: suspend CoroutineScope.(T) -> Unit) =
        scope.collectOnce(flow, func)

    fun <T> collectOnce(flow: XSharedFlow<T>, func: suspend CoroutineScope.(T) -> Unit) =
        scope.collectOnce(flow, func)

    fun <T> createStateFlow(default: T, func: suspend CoroutineScope.() -> Flow<T>) =
        scope.createStateFlow(default, func)

    fun <T> createSharedFlow(distinct: Boolean = true, func: suspend CoroutineScope.() -> Flow<T>) =
        scope.createSharedFlow(distinct, func)

    fun release() {
        scope.cancel()
    }
}
